<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  

  
  <title>Android BootAnimation分析 | Beautiful Code Creates Beautiful Life!</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="Android BootAnimation分析Android Version：Android Q代码路径：frameworks&#x2F;base&#x2F;cmds&#x2F;bootanimation 开机动画其实就是一个使用C++编写的Native程序，因此我们就从它的main函数开始看起即可。main()位于bootanimation_main.cpp文件中，这个文件里面就这么一个函数，具体代码如下所示。 123456">
<meta property="og:type" content="article">
<meta property="og:title" content="Android BootAnimation分析">
<meta property="og:url" content="http://tshfut.gitee.io/articles/2020/01/26/Android-BootAnimation%E5%88%86%E6%9E%90/index.html">
<meta property="og:site_name" content="Beautiful Code Creates Beautiful Life!">
<meta property="og:description" content="Android BootAnimation分析Android Version：Android Q代码路径：frameworks&#x2F;base&#x2F;cmds&#x2F;bootanimation 开机动画其实就是一个使用C++编写的Native程序，因此我们就从它的main函数开始看起即可。main()位于bootanimation_main.cpp文件中，这个文件里面就这么一个函数，具体代码如下所示。 123456">
<meta property="og:locale" content="en_US">
<meta property="article:published_time" content="2020-01-26T12:54:03.000Z">
<meta property="article:modified_time" content="2020-01-26T12:54:03.000Z">
<meta property="article:author" content="tshfut">
<meta property="article:tag" content="android">
<meta name="twitter:card" content="summary">
  
    <link rel="alternate" href="/articles/atom.xml" title="Beautiful Code Creates Beautiful Life!" type="application/atom+xml">
  
  
    <link rel="icon" href="/favicon.png">
  
  
    <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  
  
<link rel="stylesheet" href="/articles/css/style.css">

<meta name="generator" content="Hexo 4.2.0"></head>

<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/articles/" id="logo">Beautiful Code Creates Beautiful Life!</a>
      </h1>
      
        <h2 id="subtitle-wrap">
          <a href="/articles/" id="subtitle">Code &amp; Life</a>
        </h2>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/articles/">Home</a>
        
          <a class="main-nav-link" href="/articles/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-rss-link" class="nav-icon" href="/articles/atom.xml" title="RSS Feed"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="http://tshfut.gitee.io/articles"></form>
      </div>
    </div>
  </div>
</header>
      <div class="outer">
        <section id="main"><article id="post-Android-BootAnimation分析" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/articles/2020/01/26/Android-BootAnimation%E5%88%86%E6%9E%90/" class="article-date">
  <time datetime="2020-01-26T12:54:03.000Z" itemprop="datePublished">2020-01-26</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/articles/categories/android/">android</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      Android BootAnimation分析
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h1 id="Android-BootAnimation分析"><a href="#Android-BootAnimation分析" class="headerlink" title="Android BootAnimation分析"></a>Android BootAnimation分析</h1><p>Android Version：Android Q<br>代码路径：frameworks/base/cmds/bootanimation</p>
<p>开机动画其实就是一个使用C++编写的Native程序，因此我们就从它的main函数开始看起即可。main()位于bootanimation_main.cpp文件中，这个文件里面就这么一个函数，具体代码如下所示。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    setpriority(PRIO_PROCESS, <span class="number">0</span>, ANDROID_PRIORITY_DISPLAY);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">bool</span> noBootAnimation = bootAnimationDisabled();</span><br><span class="line">    ALOGI_IF(noBootAnimation,  <span class="string">"boot animation disabled"</span>);</span><br><span class="line">    <span class="keyword">if</span> (!noBootAnimation) &#123;</span><br><span class="line"></span><br><span class="line">        <span class="function">sp&lt;ProcessState&gt; <span class="title">proc</span><span class="params">(ProcessState::self())</span></span>;</span><br><span class="line">        ProcessState::self()-&gt;startThreadPool();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// create the boot animation object (may take up to 200ms for 2MB zip)</span></span><br><span class="line">        sp&lt;BootAnimation&gt; boot = <span class="keyword">new</span> BootAnimation(audioplay::createAnimationCallbacks());</span><br><span class="line"></span><br><span class="line">        waitForSurfaceFlinger();</span><br><span class="line"></span><br><span class="line">        boot-&gt;run(<span class="string">"BootAnimation"</span>, PRIORITY_DISPLAY);</span><br><span class="line"></span><br><span class="line">        ALOGV(<span class="string">"Boot animation set up. Joining pool."</span>);</span><br><span class="line"></span><br><span class="line">        IPCThreadState::self()-&gt;joinThreadPool();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>bootAnimatinoDisabled()函数的目的很简单，通过两个prop项判断是否启动开机动画，这里我们假设是使能了开机动画的。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">bootAnimationDisabled</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">char</span> value[PROPERTY_VALUE_MAX];</span><br><span class="line">    property_get(<span class="string">"debug.sf.nobootanimation"</span>, value, <span class="string">"0"</span>);</span><br><span class="line">    <span class="keyword">if</span> (atoi(value) &gt; <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    property_get(<span class="string">"ro.boot.quiescent"</span>, value, <span class="string">"0"</span>);</span><br><span class="line">    <span class="keyword">return</span> atoi(value) &gt; <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>下面if块的核心就下面这三句，创建一个BootAnimation对象，等待SurfaceFlinger服务起来后，然后开始执行开机动画。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">sp&lt;BootAnimation&gt; boot = <span class="keyword">new</span> BootAnimation(audioplay::createAnimationCallbacks());</span><br><span class="line">waitForSurfaceFlinger();</span><br><span class="line">boot-&gt;run(<span class="string">"BootAnimation"</span>, PRIORITY_DISPLAY);</span><br></pre></td></tr></table></figure>

<p>为啥要等SurfaceFlinger？开机动画走的是标准的Android应用显示流程，需要SurfaceFlinger进行合成处理，因此必须等SurfaceFlinger服务启动成功后才能正常播放开机动画。其实现就是隔一段时间去找ServiceManager要SurfaceFlinger服务，要到了，就返回。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">waitForSurfaceFlinger</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">// <span class="doctag">TODO:</span> replace this with better waiting logic in future, b/35253872</span></span><br><span class="line">    <span class="keyword">int64_t</span> waitStartTime = elapsedRealtime();</span><br><span class="line">    sp&lt;IServiceManager&gt; sm = defaultServiceManager();</span><br><span class="line">    <span class="function"><span class="keyword">const</span> String16 <span class="title">name</span><span class="params">(<span class="string">"SurfaceFlinger"</span>)</span></span>;</span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">int</span> SERVICE_WAIT_SLEEP_MS = <span class="number">100</span>;</span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">int</span> LOG_PER_RETRIES = <span class="number">10</span>;</span><br><span class="line">    <span class="keyword">int</span> retry = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">while</span> (sm-&gt;checkService(name) == <span class="literal">nullptr</span>) &#123;</span><br><span class="line">        retry++;</span><br><span class="line">        <span class="keyword">if</span> ((retry % LOG_PER_RETRIES) == <span class="number">0</span>) &#123;</span><br><span class="line">            ALOGW(<span class="string">"Waiting for SurfaceFlinger, waited for %"</span> PRId64 <span class="string">" ms"</span>,</span><br><span class="line">                  elapsedRealtime() - waitStartTime);</span><br><span class="line">        &#125;</span><br><span class="line">        usleep(SERVICE_WAIT_SLEEP_MS * <span class="number">1000</span>);</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">int64_t</span> totalWaited = elapsedRealtime() - waitStartTime;</span><br><span class="line">    <span class="keyword">if</span> (totalWaited &gt; SERVICE_WAIT_SLEEP_MS) &#123;</span><br><span class="line">        ALOGI(<span class="string">"Waiting for SurfaceFlinger took %"</span> PRId64 <span class="string">" ms"</span>, totalWaited);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>下面来看重点部分，创建开机动画线程并执行。<br>在创建BootAnimation对象时，传入了一个CallBack，先来看BootAnimation的构造函数，只有一个CallBack类型的入参，从传进来的名字已经可以猜到大致的用途，就是用来提供播放声音相关的功能，这个我们放在最后看，先看显示部分相关的内容。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">BootAnimation::BootAnimation(sp&lt;Callbacks&gt; callbacks)</span><br><span class="line">        : Thread(<span class="literal">false</span>), mClockEnabled(<span class="literal">true</span>), mTimeIsAccurate(<span class="literal">false</span>),</span><br><span class="line">        mTimeFormat12Hour(<span class="literal">false</span>), mTimeCheckThread(<span class="literal">nullptr</span>), mCallbacks(callbacks) &#123;</span><br><span class="line">    mSession = <span class="keyword">new</span> SurfaceComposerClient();</span><br><span class="line"></span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">string</span> powerCtl = android::base::GetProperty(<span class="string">"sys.powerctl"</span>, <span class="string">""</span>);</span><br><span class="line">    <span class="keyword">if</span> (powerCtl.empty()) &#123;</span><br><span class="line">        mShuttingDown = <span class="literal">false</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        mShuttingDown = <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    ALOGD(<span class="string">"%sAnimationStartTiming start time: %"</span> PRId64 <span class="string">"ms"</span>, mShuttingDown ? <span class="string">"Shutdown"</span> : <span class="string">"Boot"</span>,</span><br><span class="line">            elapsedRealtime());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>BootAnimation()构造函数中，创建了SurfaceComposerClient对象，用于后期与SurfaceFlinger进行通信。创建了BootAnimation实例后，会紧接着调用onFirstRef函数，这里面就干了两个事情：先是调用linkToComposerDeath注册死亡通知，接着调用preloadAnimation()加载开机动画资源。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">BootAnimation::onFirstRef</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">status_t</span> err = mSession-&gt;linkToComposerDeath(<span class="keyword">this</span>);</span><br><span class="line">    SLOGE_IF(err, <span class="string">"linkToComposerDeath failed (%s) "</span>, strerror(-err));</span><br><span class="line">    <span class="keyword">if</span> (err == NO_ERROR) &#123;</span><br><span class="line">        <span class="comment">// Load the animation content -- this can be slow (eg 200ms)</span></span><br><span class="line">        <span class="comment">// called before waitForSurfaceFlinger() in main() to avoid wait</span></span><br><span class="line">        ALOGD(<span class="string">"%sAnimationPreloadTiming start time: %"</span> PRId64 <span class="string">"ms"</span>,</span><br><span class="line">                mShuttingDown ? <span class="string">"Shutdown"</span> : <span class="string">"Boot"</span>, elapsedRealtime());</span><br><span class="line">        preloadAnimation();</span><br><span class="line">        ALOGD(<span class="string">"%sAnimationPreloadStopTiming start time: %"</span> PRId64 <span class="string">"ms"</span>,</span><br><span class="line">                mShuttingDown ? <span class="string">"Shutdown"</span> : <span class="string">"Boot"</span>, elapsedRealtime());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p>查看BootAnimation类定义可甜，他继承于Thread类，因此在执行 <strong>boot-&gt;run(“BootAnimation”, PRIORITY_DISPLAY)</strong> 后，我们就可以直接来看BootAnimation::readyToRun()函数，这里做一些准备工作，主要内容如下：</p>
<ol>
<li>通过SurfaceComposerClient::getInternalDisplayToken()获取默认屏幕的Token</li>
<li>通过urfaceComposerClient::getDisplayInfo()获取到DisplayInfo，这里主要是为了拿屏幕的宽和高</li>
<li>根据第2步中拿到的宽和高俩娃一个名为『BootAnimation』的Surface（即Layer），createSurface()的返回值为SurfaceControl类型的指针，通过其getSurface()方法可以获取到创建出来的Surface实例。</li>
<li>按照标准的egl流程，初始化opengl和egl，最后通过eglMakeCurrent将display和surface串联起来，为后面的绘制做准备。</li>
</ol>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">status_t</span> <span class="title">BootAnimation::readyToRun</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    mAssets.addDefaultAssets();</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 1. 获取内置Display的ID</span></span><br><span class="line">    mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();</span><br><span class="line">    <span class="keyword">if</span> (mDisplayToken == <span class="literal">nullptr</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line"></span><br><span class="line">    DisplayInfo dinfo;</span><br><span class="line">    <span class="comment">// 2. 获取内置屏幕的信息（这里用到了宽和高）</span></span><br><span class="line">    <span class="keyword">status_t</span> status = SurfaceComposerClient::getDisplayInfo(mDisplayToken, &amp;dinfo);</span><br><span class="line">    <span class="keyword">if</span> (status)</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 3. create the native surface</span></span><br><span class="line">    sp&lt;SurfaceControl&gt; control = session()-&gt;createSurface(String8(<span class="string">"BootAnimation"</span>),</span><br><span class="line">            dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 创建transaction，用于提交变化，告诉surfaceflinger有事情要做了。</span></span><br><span class="line">    SurfaceComposerClient::Transaction t;</span><br><span class="line">    t.setLayer(control, <span class="number">0x40000000</span>)</span><br><span class="line">        .apply();</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 4. 获取上面创建的native Surface实例</span></span><br><span class="line">    sp&lt;Surface&gt; s = control-&gt;getSurface();</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 5. initialize opengl and egl</span></span><br><span class="line">    <span class="keyword">const</span> EGLint attribs[] = &#123;</span><br><span class="line">            EGL_RED_SIZE,   <span class="number">8</span>,</span><br><span class="line">            EGL_GREEN_SIZE, <span class="number">8</span>,</span><br><span class="line">            EGL_BLUE_SIZE,  <span class="number">8</span>,</span><br><span class="line">            EGL_DEPTH_SIZE, <span class="number">0</span>,</span><br><span class="line">            EGL_NONE</span><br><span class="line">    &#125;;</span><br><span class="line">    EGLint w, h;</span><br><span class="line">    EGLint numConfigs;</span><br><span class="line">    EGLConfig config;</span><br><span class="line">    EGLSurface surface;</span><br><span class="line">    EGLContext context;</span><br><span class="line"></span><br><span class="line">    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);</span><br><span class="line"></span><br><span class="line">    eglInitialize(display, <span class="literal">nullptr</span>, <span class="literal">nullptr</span>);</span><br><span class="line">    eglChooseConfig(display, attribs, &amp;config, <span class="number">1</span>, &amp;numConfigs);</span><br><span class="line">    surface = eglCreateWindowSurface(display, config, s.get(), <span class="literal">nullptr</span>);</span><br><span class="line">    context = eglCreateContext(display, config, <span class="literal">nullptr</span>, <span class="literal">nullptr</span>);</span><br><span class="line">    eglQuerySurface(display, surface, EGL_WIDTH, &amp;w);</span><br><span class="line">    eglQuerySurface(display, surface, EGL_HEIGHT, &amp;h);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)</span><br><span class="line">        <span class="keyword">return</span> NO_INIT;</span><br><span class="line"></span><br><span class="line">    mDisplay = display;</span><br><span class="line">    mContext = context;</span><br><span class="line">    mSurface = surface;</span><br><span class="line">    mWidth = w;</span><br><span class="line">    mHeight = h;</span><br><span class="line">    mFlingerSurfaceControl = control;</span><br><span class="line">    mFlingerSurface = s;</span><br><span class="line">    mTargetInset = <span class="number">-1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> NO_ERROR;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>然后来看BootAnimation::threadLoop函数了，这个实现包含两个主要部分：第一部分是调用android()和movie()两个函数来实现不同的开机动画效果；第二部分是做一些开机动画播放完成后的一些清理工作。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">BootAnimation::threadLoop</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">bool</span> r;</span><br><span class="line">    <span class="comment">// We have no bootanimation file, so we use the stock android logo animation.</span></span><br><span class="line">    <span class="keyword">if</span> (mZipFileName.isEmpty()) &#123;</span><br><span class="line">        r = android();</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        r = movie();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);</span><br><span class="line">    eglDestroyContext(mDisplay, mContext);</span><br><span class="line">    eglDestroySurface(mDisplay, mSurface);</span><br><span class="line">    mFlingerSurface.clear();</span><br><span class="line">    mFlingerSurfaceControl.clear();</span><br><span class="line">    eglTerminate(mDisplay);</span><br><span class="line">    eglReleaseThread();</span><br><span class="line">    IPCThreadState::self()-&gt;stopProcess();</span><br><span class="line">    <span class="keyword">return</span> r;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p>重点看第一部分，两种形式的开机动画效果。</p>
<h2 id="android"><a href="#android" class="headerlink" title="android"></a>android</h2><p>实现在BootAnimation::android()函数中。</p>
<h2 id="movie"><a href="#movie" class="headerlink" title="movie"></a>movie</h2>
      
    </div>
    <footer class="article-footer">
      <a data-url="http://tshfut.gitee.io/articles/2020/01/26/Android-BootAnimation%E5%88%86%E6%9E%90/" data-id="ck5w8e81y00042wuf4crg7bcn" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/articles/tags/android/" rel="tag">android</a></li></ul>

    </footer>
  </div>
  
    
<nav id="article-nav">
  
  
    <a href="/articles/2020/01/26/SurfaceFlinger%E5%90%88%E6%88%90%E6%B5%81%E7%A8%8B/" id="article-nav-older" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Older</strong>
      <div class="article-nav-title">SurfaceFlinger合成流程</div>
    </a>
  
</nav>

  
</article>

</section>
        
          <aside id="sidebar">
  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Categories</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/articles/categories/android/">android</a></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tags</h3>
    <div class="widget">
      <ul class="tag-list" itemprop="keywords"><li class="tag-list-item"><a class="tag-list-link" href="/articles/tags/android/" rel="tag">android</a></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tag Cloud</h3>
    <div class="widget tagcloud">
      <a href="/articles/tags/android/" style="font-size: 10px;">android</a>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Archives</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/articles/archives/2020/01/">January 2020</a></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Recent Posts</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/articles/2020/01/26/Android-BootAnimation%E5%88%86%E6%9E%90/">Android BootAnimation分析</a>
          </li>
        
          <li>
            <a href="/articles/2020/01/26/SurfaceFlinger%E5%90%88%E6%88%90%E6%B5%81%E7%A8%8B/">SurfaceFlinger合成流程</a>
          </li>
        
          <li>
            <a href="/articles/2020/01/25/Android%E7%B3%BB%E7%BB%9F%E5%BC%80%E5%8F%91%E7%B3%BB%E5%88%97/">Android系统开发系列</a>
          </li>
        
          <li>
            <a href="/articles/2020/01/25/%E4%BD%BF%E7%94%A8Hexo-Gitee%E5%88%9B%E5%BB%BA%E4%B8%AA%E4%BA%BA%E7%BD%91%E7%AB%99/">使用Hexo-Gitee创建个人网站</a>
          </li>
        
      </ul>
    </div>
  </div>

  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2020 tshfut<br>
      Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer>
    </div>
    <nav id="mobile-nav">
  
    <a href="/articles/" class="mobile-nav-link">Home</a>
  
    <a href="/articles/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>


  
<link rel="stylesheet" href="/articles/fancybox/jquery.fancybox.css">

  
<script src="/articles/fancybox/jquery.fancybox.pack.js"></script>




<script src="/articles/js/script.js"></script>




  </div>
</body>
</html>